﻿using System.Linq;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using Geotools.Geometries;
using System.Collections.Generic;
using System;

namespace AzukiMap.Tools
{
    public class XmlCommon
    {
        # region ToXmls
        public XElement BrushToXml(string wrapElement, Brush brush)
        {
            if (brush == null)
            {
                return null;
            }
            return
                new XElement(
                    wrapElement,
                    BrushToXml(brush)
                );
        }

        public XElement BrushToXml(Brush brush)
        {
            if (brush == null)
            {
                return null;
            }
            XElement brushElement = new XElement("Brush");
            if (brush.GetType() == typeof(SolidColorBrush))
            {
                SolidColorBrush sBrush = (SolidColorBrush)brush;
                XElement solidColorElement = new XElement("SolidColorBrush",
                    ColorToXml(sBrush.Color),
                    new XElement("Opacity", sBrush.Opacity)
                    );
                brushElement.Add(solidColorElement);
            }
            return brushElement;
        }

        public XElement ColorToXml(string wrapElement, Color color)
        {
            if (color == null)
            {
                return null;
            }
            return
                new XElement(
                    wrapElement,
                    ColorToXml(color)
                );
        }

        public XElement ColorToXml(Color color)
        {
            if (color == null)
            {
                return null;
            }
            XElement colorElement = 
                new XElement("Color", 
                    new XAttribute("R", color.R), 
                    new XAttribute("G", color.G), 
                    new XAttribute("B", color.B), 
                    new XAttribute("A", color.A)
                    );
            return colorElement;
        }

        public XElement DoubleCollectionToXml(string wrapElement, DoubleCollection dc)
        {
            if (dc == null)
            {
                return null;
            }
            return
                new XElement(
                    wrapElement,
                    DoubleCollectionToXml(dc)
                );
        }

        public XElement DoubleCollectionToXml(DoubleCollection dc)
        {
            if (dc == null)
            {
                return null;
            }
            XElement dcElement = new XElement("DoubleCollection",
                from d in dc
                select new XElement("Value", d.ToString())
                );
            return dcElement;
        }

        public XElement StringListToXml(XName elemName, XName childElemName, List<string> list)
        {
            if (list == null)
            {
                return null;
            }
            XElement listElem = new XElement(elemName);
            foreach (string value in list)
            {
                listElem.Add(new XElement(childElemName, value));
            }
            return listElem;
        }

        public XElement ImageToXml(string wrapElement, Image img)
        {
            if (img == null)
            {
                return null;
            }
            return
                new XElement(
                    wrapElement,
                    ImageToXml(img)
                );
        }

        public XElement ImageToXml(Image img)
        {
            if (img == null)
            {
                return null;
            }
            XElement imgElement =
                new XElement("Image",
                    new XAttribute("Width", img.Width),
                    new XAttribute("Height", img.Height),
                    new XElement("ImageSource",
                        ImageSourceToXml(img.Source)
                        ),
                    new XAttribute("Opacity", img.Opacity)
                    );
            return imgElement;
        }

        public XElement ImageSourceToXml(ImageSource source)
        {
            if (source == null)
            {
                return null;
            }
            if (source.GetType() == typeof(BitmapImage))
            {
                BitmapImage bitmap = (BitmapImage)source;
                XElement sourceElement =
                    new XElement("BitmapImage",
                        new XAttribute("Uri", bitmap.UriSource)
                        );
                return sourceElement;
            }
            else // DrawingImage
            {
                // DrawingImage is not implemented on Silverlight.
                XElement sourceElement = new XElement("DrawingImage");
                return sourceElement;
            }

        }

        public XElement CreateElement(string elementName, object value)
        {
            XElement element;
            if (value == null)
            {
                element = new XElement(elementName, "");
            }
            else
            {
                element = new XElement(elementName, value);
            }
            return element;
        }

        public XAttribute CreateAttr(string attrName, object value)
        {
            XAttribute attr;
            if (value == null)
            {
                //attr = new XAttribute(attrName, "");
                attr = null;
            }
            else
            {
                attr = new XAttribute(attrName, value);
            }
            return attr;
        }


        public XElement GeometryToXml(string elementName, GTGeometry geometry)
        {
            XElement polygonXml;
            if (geometry == null)
            {
                //polygonXml = new XElement(elementName, "");
                polygonXml = null;
            }
            else
            {
                polygonXml = new XElement(elementName, geometry.ToText());
            }
            return polygonXml;
        }

        public XElement EnvelopeToXml(string elementName, GTEnvelope envelope)
        {
            if (envelope == null)
            {
                return null;
            }
            XElement envelopeXml = new XElement(elementName);
            envelopeXml.Add(
                CreateElement("MinX", envelope.MinX),
                CreateElement("MinY", envelope.MinY),
                CreateElement("MaxX", envelope.MaxX),
                CreateElement("MaxY", envelope.MaxY)
            );
            return envelopeXml;
        }

        public GTEnvelope GetEnvelopeElement(XElement parentElem, string elementName)
        {
            XElement envelopeElem = parentElem.Element(elementName);

            double minX, minY, maxX, maxY;
            try
            {
                minX = GetDoubleElement(envelopeElem, "MinX");
                minY = GetDoubleElement(envelopeElem, "MinX");
                maxX = GetDoubleElement(envelopeElem, "MinX");
                maxY = GetDoubleElement(envelopeElem, "MinX");
            }
            catch (Exception e)
            {
                return null;
            }

            GTEnvelope envelope = new GTEnvelope(minX, maxX, minY, maxY);

            return envelope;
        }

        # endregion

        #region parse Xmls
        public string GetStringAttr(XElement element, string attrName)
        {
            return element.Attribute(attrName).Value;
        }

        public int GetIntAttr(XElement element, string attrName)
        {
            return int.Parse(element.Attribute(attrName).Value);
        }

        public double GetDoubleAttr(XElement element, string attrName)
        {
            XAttribute attr = element.Attribute(attrName);
            if (attr == null)
            {
                return double.NaN;
            }
            return double.Parse(attr.Value);
        }

        public byte GetByteAttr(XElement element, string attrName)
        {
            return byte.Parse(element.Attribute(attrName).Value);
        }

        public bool GetBoolAttr(XElement element, string attrName)
        {
            bool value;
            try
            {
                value = bool.Parse(element.Attribute(attrName).Value);
            }
            catch (NullReferenceException ex)
            {
                return false;
            }
            return value;
        }

        public object GetEnumAttr(XElement element, string attrName, Type enumType)
        {
            object enumVal = Enum.Parse(enumType, element.Attribute(attrName).Value, true);
            return enumVal;
        }

        public string GetStringElement(XElement parentElem, string elemName)
        {
            return parentElem.Element(elemName).Value;
        }

        public int GetIntElement(XElement parentElem, string elemName)
        {
            return int.Parse(parentElem.Element(elemName).Value);
        }

        public double GetDoubleElement(XElement parentElem, string elemName)
        {
            return double.Parse(parentElem.Element(elemName).Value);
        }

        public bool GetBoolElement(XElement parentElem, string elemName)
        {
            return bool.Parse(parentElem.Element(elemName).Value);
        }

        public Color GetColorElement(XElement parentElem)
        {
            Color c = new Color();
            XElement colorElem = parentElem.Element("Color");
            c.R = GetByteAttr(colorElem, "R");
            c.G = GetByteAttr(colorElem, "G");
            c.B = GetByteAttr(colorElem, "B");
            c.A = GetByteAttr(colorElem, "A");
            return c;
        }

        public Brush GetBrushElement(XElement parantElem)
        {
            if (parantElem == null)
            {
                return null;
            }

            XElement brushElem = parantElem.Element("Brush");

            // TODO: image brush
            XElement solidColorElem = brushElem.Element("SolidColorBrush");
            SolidColorBrush brush = new SolidColorBrush();
            Color c = GetColorElement(solidColorElem);
            double opacity = GetDoubleElement(solidColorElem, "Opacity");
            brush.Color = c;
            brush.Opacity = opacity;

            return brush;
        }

        public GTGeometry GetGeomElement(XElement parentElem, string elemName)
        {
            XElement geomElem = parentElem.Element(elemName);
            if (geomElem == null)
            {
                return null;
            }
            // TODO: need SRID?
            GeometryFactory gFactory = new GeometryFactory();
            GTGeometry geom;
            if (geomElem.Value != null && geomElem.Value != "")
            {
                geom = gFactory.CreateFromWKT(geomElem.Value);
            }
            else
            {
                geom = null;
            }

            return geom;
        }

        public object GetEnumElement(XElement parentElem, string elemName, Type enumType)
        {
            XElement enumElem = parentElem.Element(elemName);

            string value = enumElem.Value;
            object enumVal = Enum.Parse(enumType, value, true);

            return enumVal;
        }

        public Uri GetUriElement(XElement parentElem, string elemName)
        {
            XElement elem = parentElem.Element(elemName);
            string uriStr = elem.ToString();
            Uri uri;
            if (uriStr == null || uriStr == "")
            {
                return null;
            }
            try
            {
                uri = new Uri(uriStr);
            }
            catch (Exception e)
            {
                return null;
            }
            return uri;
        }

        public Image GetImageElement(XElement parentElem, string elemName)
        {
            XElement elem = parentElem.Element(elemName);
            XElement imgElem = elem.Element("Image");
            Uri imageSource = GetImageSourceElement(imgElem);

            Image image = new Image();
            image.Width = GetDoubleAttr(imgElem, "Width");
            image.Height = GetDoubleAttr(imgElem, "Height");
            image.Source = new BitmapImage(imageSource);

            return image;
        }

        public Uri GetImageSourceElement(XElement parentElem)
        {
            XElement source = parentElem.Element("BitmapImage");
            if (source == null)
            {
                return null;
            }
            string uriStr = source.Attribute("Uri").Value;
            Uri imageSource = new Uri(uriStr);
            return imageSource;
        }

        /*
        public XElement ImageToXml(Image img)
        {
            XElement imgElement =
                new XElement("Image",
                    new XAttribute("Width", img.Width),
                    new XAttribute("Height", img.Height),
                    new XElement("ImageSource",
                        ImageSourceToXml(img.Source)
                        ),
                    new XAttribute("Opacity", img.Opacity)
                    );
            return imgElement;
        }

        public XElement ImageSourceToXml(ImageSource source)
        {
            if (source.GetType() == typeof(BitmapImage))
            {
                BitmapImage bitmap = (BitmapImage)source;
                XElement sourceElement =
                    new XElement("BitmapImage",
                        new XAttribute("Uri", bitmap.UriSource)
                        );
                return sourceElement;
            }
            else // DrawingImage
            {
                // DrawingImage is not implemented on Silverlight.
                XElement sourceElement = new XElement("DrawingImage");
                return sourceElement;
            }

        }
         */

        public DoubleCollection GetDoubleCollection(XElement parentElem, string elemName)
        {
            XElement elem = parentElem.Element(elemName);
            DoubleCollection dc = new DoubleCollection();
            foreach (XElement v in elem.Elements())
            {
                double value = double.Parse(v.Value);
                dc.Add(value);
            }
            return dc;
        }

        public void SetElementValuesToList(List<string> list, IEnumerable<XElement> elements, string targetElementName)
        {
            foreach (XElement elem in elements)
            {
                if (elem.Name.ToString() == targetElementName)
                {
                    list.Add(elem.Value);
                }
            }
        }

        public Dictionary<string,string> SetElementValuesToDict(IEnumerable<XElement> elements)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            foreach (XElement elem in elements)
            {
                dict.Add(elem.Name.ToString(), elem.Value);
            }
            return dict;
        }

        #endregion
    }
}
